package com.drakulo.games.ais.ui.state;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.newdawn.slick.Color;
import org.newdawn.slick.Font;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.geom.Rectangle;
import org.newdawn.slick.tiled.TiledMap;

import com.drakulo.games.ais.AloneInSpace;
import com.drakulo.games.ais.core.Colony;
import com.drakulo.games.ais.core.GameData;
import com.drakulo.games.ais.core.GameEngine;
import com.drakulo.games.ais.core.NumberHelper;
import com.drakulo.games.ais.core.Resource;
import com.drakulo.games.ais.core.ResourceHelper;
import com.drakulo.games.ais.core.Settings;
import com.drakulo.games.ais.core.building.Building;
import com.drakulo.games.ais.core.building.BuildingData;
import com.drakulo.games.ais.core.building.BuildingHelper;
import com.drakulo.games.ais.core.building.BuildingLevelData;
import com.drakulo.games.ais.core.building.BuildingType;
import com.drakulo.games.ais.core.delayed.BuildingAction;
import com.drakulo.games.ais.core.delayed.DelayedAction;
import com.drakulo.games.ais.core.delayed.MapAction;
import com.drakulo.games.ais.core.delayed.PreparationAction;
import com.drakulo.games.ais.core.delayed.ColonyAction;
import com.drakulo.games.ais.core.delayed.SpecialActionManager;
import com.drakulo.games.ais.core.io.BuildingIO;
import com.drakulo.games.ais.core.tech.TechnologyHelper;
import com.drakulo.games.ais.ui.FontHelper;
import com.drakulo.games.ais.ui.I18n;
import com.drakulo.games.ais.ui.ImageManager;
import com.drakulo.games.ais.ui.Style;
import com.drakulo.games.ais.ui.TileHelper;
import com.drakulo.games.ais.ui.UIHelper;
import com.drakulo.games.ais.ui.component.ActionHandler;
import com.drakulo.games.ais.ui.component.Minimap;
import com.drakulo.games.ais.ui.component.ProgressBar;
import com.drakulo.games.ais.ui.component.UIComponent;
import com.drakulo.games.ais.ui.component.button.Button;
import com.drakulo.games.ais.ui.component.button.ImageButton;
import com.drakulo.games.ais.ui.component.button.TextButton;
import com.drakulo.games.ais.ui.component.window.BuildWindow;
import com.drakulo.games.ais.ui.twlbridge.RootPane;

import de.matthiasmann.twl.Label;

public class SectorState extends GameState {

	/** -------------------------------------------- */
	/** TWL Widgets -------------------------------- */
	/** -------------------------------------------- */
	/**
	 * Map of labels showing resource amounts, max space, space available and
	 * modifiers
	 */
	private Map<Resource, Label> inStoreLabels;
	private Map<Resource, Label> maxStoreLabels;
	private Map<Resource, Label> availableSpaceLabels;
	private Map<Resource, Label> modifiersLabels;
	/** Rows labels of resource extended mode */
	private Label storeTitle;
	private Label maxStoreTitle;
	private Label availableSpaceTitle;
	private Label modifierTitle;
	/** Game menu buttons */
	private List<Button> gameMenuButtons;
	/** Selected building labels displaying it's attributes */
	private Map<Resource, Label> buildingProdLabels;
	private Map<Resource, Label> buildingConsLabels;
	private Map<Resource, Label> buildingStoreLabels;
	private Label[] buildingColLabels;
	private Map<Resource, Label> buildingRowLabels;
	/** Upgrade overview labels */
	private Map<Resource, Label> upgradeLabels;

	/** -------------------------------------------- */
	/** Other properties --------------------------- */
	/** -------------------------------------------- */
	/** Height of the bottom bar */
	private static final int BOTTOM_BAR_HEIGHT = Minimap.HEIGHT.intValue() + 20;
	/** Padding */
	private static final int PADDING = 10;
	/** The top resource zone width */
	private static final int TOP_BAR_WIDTH = 653;
	/** The toggle button zone */
	private static final int TOGGLE_BUTTON_ZONE_WIDTH = 24;
	/** The map viewport width */
	public static final int VIEWPORT_WIDTH = Settings.WIDTH;
	/** The map viewport height */
	public static final int VIEWPORT_HEIGHT = Settings.HEIGHT
			- BOTTOM_BAR_HEIGHT - TOP_BAR_HEIGHT;

	/** The minimap */
	private Minimap minimap;
	/** Top scroll zone */
	private Rectangle topScrollZone;
	/** Bottom scroll zone */
	private Rectangle bottomScrollZone;
	/** Left scroll zone */
	private Rectangle leftScrollZone;
	/** Right scroll zone */
	private Rectangle rightScrollZone;
	/** The building selected by the player */
	private Building selectedBuilding;
	/** A map of Progress bar, one for each resource */
	private Map<Resource, ProgressBar> resourceBars;
	/** Progress bar for robots use */
	private ProgressBar robotBar;
	/** Current research progress bar */
	private ProgressBar researchBar;
	/** Resource zone extended display */
	private boolean extendedResourceDisplay;
	/** The game menu display flag */
	private boolean showGameMenu;
	/** The building action Window */
	private BuildWindow buildWindow;
	/** The building action window display flag */
	private boolean showActionWindow;
	/** The selected map action */
	private MapAction selectedAction;
	/** Current X coordinate of the mouse on the screen */
	private int mouseX;
	/** Current Y coordinate of the mouse on the screen */
	private int mouseY;
	/** Current X coordinate of the square hovered on screen */
	private int squareXOnScreen;
	/** Current Y coordinate of the square hovered on screen */
	private int squareYOnScreen;
	/** Current X coordinate of the square hovered on map */
	private int squareXOnMap;
	/** Current Y coordinate of the square hovered on map */
	private int squareYOnMap;
	/** The selected building current action progress bar */
	private ProgressBar selectedBuildingPB;
	/** The Develop button */
	private ImageButton developButton;
	/** The research button */
	private ImageButton researchVisionButton;
	/** The planet button */
	private ImageButton planetVisionButton;
	/** This button cancels the selected building current action */
	private ImageButton cancelButton;
	/** Building buttons array */
	private ImageButton[][] buildingButtons;
	/** The list of UIComponents to render and update */
	private List<UIComponent> components;

	public SectorState(int id) {
		super(id);
		this.extendedResourceDisplay = false;
		this.showGameMenu = false;
		this.components = new ArrayList<UIComponent>();
	}

	@Override
	protected RootPane createRootPane() {
		this.rootPane = super.createRootPane();

		// final int startX = Settings.WIDTH - Minimap.WIDTH.intValue() -
		// PADDING
		// + 5;
		// final int startY = Settings.HEIGHT - Minimap.HEIGHT.intValue()
		// - PADDING + 5;

		int width = TOP_BAR_WIDTH + TOGGLE_BUTTON_ZONE_WIDTH;
		int x = Settings.WIDTH / 2 - width / 2 + 3;
		int y = PADDING + 3;

		this.inStoreLabels = new HashMap<Resource, Label>();
		this.maxStoreLabels = new HashMap<Resource, Label>();
		this.availableSpaceLabels = new HashMap<Resource, Label>();
		this.modifiersLabels = new HashMap<Resource, Label>();
		Resource[] resources = Resource.values();
		for (Resource r : resources) {
			this.inStoreLabels.put(r, createAndAddResourceLabel(null));
			this.maxStoreLabels.put(r, createAndAddResourceLabel(null));
			this.availableSpaceLabels.put(r, createAndAddResourceLabel(null));
			this.modifiersLabels.put(r, createAndAddResourceLabel(null));
		}
		this.storeTitle = createAndAddResourceLabel(I18n
				.get("resource.stored_quantity"));
		this.maxStoreTitle = createAndAddResourceLabel(I18n
				.get("resource.max_space"));
		this.availableSpaceTitle = createAndAddResourceLabel(I18n
				.get("resource.available_space"));
		this.modifierTitle = createAndAddResourceLabel(I18n
				.get("resource.modifier"));

		// Selected building attributes labels
		this.buildingProdLabels = new HashMap<Resource, Label>();
		this.buildingConsLabels = new HashMap<Resource, Label>();
		this.buildingStoreLabels = new HashMap<Resource, Label>();
		this.buildingRowLabels = new HashMap<Resource, Label>();
		this.upgradeLabels = new HashMap<Resource, Label>();
		for (Resource r : resources) {
			this.buildingProdLabels.put(r,
					createAndAddResourceLabel(null, 80, "resourceLabel"));
			this.buildingConsLabels.put(r,
					createAndAddResourceLabel(null, 80, "resourceLabel"));
			this.buildingStoreLabels.put(r,
					createAndAddResourceLabel(null, 80, "resourceLabel"));
			this.buildingRowLabels.put(
					r,
					createAndAddResourceLabel(
							FontHelper.firstToUpper(r.getI18n()), 80,
							"resourceLabel"));
			this.upgradeLabels.put(r,
					createAndAddResourceLabel(null, 80, "resourceLabel"));
		}

		this.buildingColLabels = new Label[3];
		this.buildingColLabels[0] = createAndAddResourceLabel(
				I18n.get("resource.income.short"), 80, "titleResourceLabel");
		this.buildingColLabels[1] = createAndAddResourceLabel(
				I18n.get("resource.consumption.short"), 80,
				"titleResourceLabel");
		this.buildingColLabels[2] = createAndAddResourceLabel(
				I18n.get("resource.store"), 80, "titleResourceLabel");

		return this.rootPane;
	}

	private Label createAndAddResourceLabel(String title, int width,
			String theme) {
		Label l;
		if (title == null) {
			l = new Label();
		} else {
			l = new Label(title);
		}
		l.setVisible(false);
		l.setSize(width, 15);
		l.setTheme(theme);
		this.rootPane.add(l);
		return l;
	}

	/**
	 * @return A themed label for extended resources display
	 */
	private Label createAndAddResourceLabel(String title) {
		return this.createAndAddResourceLabel(title, 122, "resourceLabel");
	}

	@Override
	public void initState() throws SlickException {

		// TODO externalize this part
		// Load the tiledmap
		TiledMap tiledMap = new TiledMap("data/testmap.tmx");

		Colony c = new Colony();
		c.setAvailableRobots(3);
		c.setTotalRobots(3);
		c.setMap(tiledMap);
		c.setName("Anthem Base");

		Resource[] resources = Resource.values();
		for (Resource r : resources) {
			c.setResource(r, BigDecimal.valueOf(1000));
		}

		c.setResearchCenterBuilt(false);
		GameData.addColony(c);
		GameData.setSelectedColony(c);
		// /////////////////////////

		// End of to externalize zone

		final int pad = 10;
		final int minimapX = pad;
		final int minimapY = Settings.HEIGHT - pad - Minimap.HEIGHT.intValue();
		this.minimap = new Minimap(minimapX, minimapY);

		// Initialization of border scroll zones
		initializeScrollZones();

		// Progress bars
		this.resourceBars = new HashMap<Resource, ProgressBar>();
		for (Resource r : resources) {
			ProgressBar pb = UIHelper.createBar(r.getI18n(), r.getColor(),
					false);
			this.resourceBars.put(r, pb);
		}
		this.robotBar = UIHelper.createBar("Robots", Color.white, true);

		this.selectedBuildingPB = new ProgressBar();
		this.selectedBuildingPB.setHeight(10);
		this.selectedBuildingPB.setWidth(202);
		this.selectedBuildingPB.setEmptyColor(Color.darkGray);
		this.selectedBuildingPB.setFilledColor(Color.magenta);

		int x = Settings.WIDTH / 2 - ImageButton.IB_DEFAULT_SIZE / 2;
		int y = Settings.HEIGHT - 116 - PADDING - ImageButton.IB_DEFAULT_SIZE
				- PADDING;
		this.developButton = new ImageButton("cog", x, y);
		developButton.setTitle(I18n.get("ui.build_panel"));
		this.developButton.setActionHandler(new ActionHandler() {

			@Override
			public void run() {
				showBuildWindow(!SectorState.this.showActionWindow);
			}
		});
		add(developButton);

		x -= PADDING + ImageButton.IB_DEFAULT_SIZE;
		this.researchVisionButton = new ImageButton("lightbulb", x, y);
		researchVisionButton.setTitle(I18n.get("vision.research"));
		this.researchVisionButton.disable();
		this.researchVisionButton.setActionHandler(new ActionHandler() {

			@Override
			public void run() {
				GameData.getGame().enterState(AloneInSpace.RESEARCH_STATE);
			}
		});
		add(researchVisionButton);

		x -= PADDING + ImageButton.IB_DEFAULT_SIZE;
		this.planetVisionButton = new ImageButton("globe_3", x, y);
		planetVisionButton.setTitle(I18n.get("vision.planet"));
		this.planetVisionButton.disable();
		this.planetVisionButton.setActionHandler(new ActionHandler() {

			@Override
			public void run() {
				SectorState.this.selectedAction = null;
				SectorState.this.selectedBuilding = null;
				GameData.getGame().enterState(AloneInSpace.PLANET_STATE);
			}
		});
		add(planetVisionButton);

		// Cancel button

		final int startX = Settings.WIDTH - Minimap.WIDTH.intValue() - PADDING
				+ 10;
		final int startY = Settings.HEIGHT - Minimap.HEIGHT.intValue()
				- PADDING + 9;
		this.buildingButtons = new ImageButton[3][3];
		for (int col = 0; col < 3; col++) {
			for (int row = 0; row < 3; row++) {
				this.buildingButtons[col][row] = new ImageButton(null, startX
						+ col * 46, startY + row * 46);
				this.buildingButtons[col][row].disable();
				this.buildingButtons[col][row].hide();

			}
		}

		this.cancelButton = this.buildingButtons[2][2];
		this.cancelButton.setImageRef("cancel");
		this.cancelButton.setActionHandler(new ActionHandler() {

			@Override
			public void run() {
				stopSelectedBuildingAction();
			}
		});

		this.buildingButtons[0][2].setImageRef("upgrade");
		this.buildingButtons[0][2].setActionHandler(new ActionHandler() {

			@Override
			public void run() {
				hideUpgradeLabels();
				upgradeBuilding(SectorState.this.selectedBuilding);
			}
		});

		int width = TOP_BAR_WIDTH + TOGGLE_BUTTON_ZONE_WIDTH;
		x = Settings.WIDTH / 2 - width / 2 + 4;
		y = PADDING + 3;
		final TextButton resourceTogglerButton = new TextButton("+");
		resourceTogglerButton.setPosition(x, y);
		resourceTogglerButton.setSize(21, 21);
		resourceTogglerButton.setActionHandler(new ActionHandler() {

			@Override
			public void run() {
				SectorState.this.extendedResourceDisplay = !SectorState.this.extendedResourceDisplay;
				Resource[] resources = Resource.values();
				for (Resource r : resources) {
					boolean show = SectorState.this.extendedResourceDisplay;
					SectorState.this.inStoreLabels.get(r).setVisible(show);
					SectorState.this.maxStoreLabels.get(r).setVisible(show);
					SectorState.this.availableSpaceLabels.get(r).setVisible(
							show);
					SectorState.this.modifiersLabels.get(r).setVisible(show);
					SectorState.this.storeTitle.setVisible(show);
					SectorState.this.maxStoreTitle.setVisible(show);
					SectorState.this.availableSpaceTitle.setVisible(show);
					SectorState.this.modifierTitle.setVisible(show);

					if (show) {
						resourceTogglerButton.setText("-");
					} else {
						resourceTogglerButton.setText("+");
					}
				}
			}
		});
		add(resourceTogglerButton);

		width = 270;
		int height = 300;
		x = Settings.WIDTH / 2 - width / 2;
		y = Settings.HEIGHT - BOTTOM_BAR_HEIGHT - height;
		this.buildWindow = new BuildWindow(this, width, height, x, y);
	}

	@Override
	public void renderState(Graphics g) throws SlickException {
		// Render the tiled map view port
		Colony c = GameData.getSelectedColony();
		GameData.getCurrentMap().render(c.getViewportX(), c.getViewportY(),
				TileHelper.DECO_LAYER);

		// Render the buildings
		renderBuildings(g);

		// Render the robots
		renderRobots(g);

		// If an action is selected, a shadow rendering is done
		if (this.selectedAction != null) {
			Image gfx = ImageManager.getGfx(this.selectedAction.getGfxKey());

			final int tileX = this.squareXOnMap;
			final int tileY = this.squareYOnMap;
			if (this.selectedAction instanceof PreparationAction) {
				// Preparation action
				if (TileHelper.tileIsPreparable(tileX, tileY)) {
					gfx.draw(this.squareXOnScreen, this.squareYOnScreen);
				} else {
					gfx.draw(this.squareXOnScreen, this.squareYOnScreen,
							Color.red);
				}

			} else if (this.selectedAction instanceof BuildingAction) {
				// Building action
				BuildingAction ba = (BuildingAction) this.selectedAction;
				if (BuildingType.COMMAND_CENTER.equals(ba.getBuilding()
						.getType())) {
					// Render the effect zone around the command center
					if (TileHelper.isValidCommandCenterTile(tileX, tileY)) {
						g.setColor(Style.FILTER_GREEN);
					} else {
						// The zone is not correct for Command Center
						// construction.
						g.setColor(Style.FILTER_RED);
					}

					int x = getScreenX(tileX - 1);
					int y = getScreenY(tileY - 1);
					g.fillRect(x, y, Settings.TILE_SIZE * 3,
							Settings.TILE_SIZE * 3);
					gfx.draw(this.squareXOnScreen, this.squareYOnScreen);
					// The command center construction is an exception
				} else if (TileHelper.tileIsBuildable(tileX, tileY, ba
						.getBuilding().getType())) {
					// Can build here
					gfx.draw(this.squareXOnScreen, this.squareYOnScreen);
				} else {
					// Cannot build here
					gfx.draw(this.squareXOnScreen, this.squareYOnScreen,
							Color.red);
				}
			}
		}

		// The UI rendering is done in last order
		renderUI(g);

		// DEBUG Data
		// final int tileX = this.squareXOnMap;
		// final int tileY = this.squareYOnMap;
		// Font debugFont = FontHelper
		// .getFont(FontHelper.ANONYMOUS, Color.red, 20);
		// debugFont.drawString(0, 50, "[" + tileX + "," + tileY + "]");
	}

	/**
	 * Renders the user interface
	 * 
	 * @param g
	 *            The graphics canvas
	 * @throws SlickException
	 */
	private void renderUI(Graphics g) throws SlickException {
		int x = 0;
		int y = Settings.HEIGHT - Minimap.HEIGHT.intValue() - PADDING * 2;
		UIHelper.drawBox(g, x, y, Settings.WIDTH, Settings.HEIGHT - y);

		// The minimap
		this.minimap.render(g);

		// The action zone
		y = Settings.HEIGHT - Minimap.HEIGHT.intValue() - PADDING;
		x = Settings.WIDTH - Minimap.WIDTH.intValue() - PADDING;
		g.setColor(Style.BORDER_COLOR);
		UIHelper.drawBox(g, x, y, 150, 150);

		final int startX = Settings.WIDTH - Minimap.WIDTH.intValue() - PADDING
				+ 7;
		final int startY = Settings.HEIGHT - Minimap.HEIGHT.intValue()
				- PADDING + 7;
		for (int i = 0; i < 3; i++) {
			for (int j = 0; j < 3; j++) {
				UIHelper.drawDarkBox(g, startX + i * 46, startY + j * 46, 43,
						43);
			}
		}

		// The game menu
		if (this.showGameMenu) {
			int menuHeight = 35 + this.gameMenuButtons.size() * 25;
			UIHelper.drawDarkBox(g, PADDING / 2, PADDING / 2, 120, menuHeight);
		}

		// The action window
		this.buildWindow.render(g);

		// Attributes Background
		int ox = 150 + PADDING * 2;
		int oy = Settings.HEIGHT - 116 - PADDING;
		UIHelper.drawDarkBox(g, ox, oy, 368, 116);

		// Overview background
		ox = 150 + PADDING * 2 + 368 + PADDING;
		oy = Settings.HEIGHT - Minimap.HEIGHT.intValue() - PADDING;
		UIHelper.drawDarkBox(g, ox, oy, 306, 150);

		if (this.selectedBuilding != null) {
			renderBuildingAttributes(g);
			renderBuildingOverview(g);
		}

		// Rendering of building buttons
		for (int col = 0; col < 3; col++) {
			for (int row = 0; row < 3; row++) {
				this.buildingButtons[col][row].render(g);
			}
		}

		// Upgrade button
		if (this.selectedBuilding != null) {
			BuildingLevelData data = BuildingIO.getBuildingData(
					this.selectedBuilding.getType()).getLevelData(
					this.selectedBuilding.getLevel());
			if (this.buildingButtons[0][2].isHovered()) {
				// The upgrade button is hovered : show the resources needed
				showUpgradeCost(data.getUpgradeCost(), g,
						this.buildingButtons[0][2]);
			} else {
				hideUpgradeLabels();
			}

			// Rendering of special building actions
			if (data.getSpecialActions() != null) {
				// There id some special action to show
				int col = 0;
				int row = 0;
				for (String name : data.getSpecialActions()) {
					final ColonyAction sa = SpecialActionManager.get(
							GameData.getSelectedColony(), name);
					ImageButton btn = this.buildingButtons[col][row];
					btn.setImageRef(sa.getGfxKey());
					btn.setActionHandler(new ActionHandler() {

						@Override
						public void run() {
							if (ResourceHelper.enoughResourcesFor(sa
									.getCostMap())) {
								sa.setLinkedBuilding(SectorState.this.selectedBuilding);
								final Colony cc = GameData.getSelectedColony();
								for (Resource r : Resource.values()) {
									BigDecimal d = sa.getCostMap().get(r);
									if (d == null) {
										continue;
									}
									cc.updateResource(r, d.negate());
								}
								GameData.getSelectedColony().addSpecialAction(
										sa);
							} else {
								// TODO Play error sound
							}
						}
					});
					btn.show();
					if (getSelectedBuildingAction() == null) {
						btn.enable();
					} else {
						btn.disable();
					}
					if (btn.isHovered()) {
						showUpgradeCost(sa.getCostMap(), g, btn);
					}
					col++;
					if (col == 3) {
						col = 0;
						row++;
					}
				}
			}
		}

		// Render the UIComponents
		for (UIComponent comp : this.components) {
			comp.render(g);
		}
	}

	@Override
	public void updateState(Input input, int time) throws SlickException {
		this.mouseX = input.getMouseX();
		this.mouseY = input.getMouseY();
		this.squareXOnScreen = getHoveredSquareX(getMouseXOnMap(input
				.getMouseX()));
		this.squareYOnScreen = getHoveredSquareY(getMouseYOnMap(input
				.getMouseY()));
		this.squareXOnMap = getMouseXOnMap(this.squareXOnScreen)
				/ Settings.TILE_SIZE;
		this.squareYOnMap = getMouseYOnMap(this.squareYOnScreen)
				/ Settings.TILE_SIZE;

		// Map scroll update
		handleScrollUpdate(input);

		// Minimap update
		this.minimap.update(input);

		// Resource progress bars updates
		Resource[] resources = Resource.values();
		for (Resource r : resources) {
			ProgressBar pb = this.resourceBars.get(r);
			pb.update(input);
		}
		this.robotBar.update(input);

		if (GameData.getSelectedColony().isCommandCenterBuilt()) {
			SectorState.this.buildWindow.setCommandCenterBuilt(true);
		} else {
			if (GameData.getSelectedColony().isCommandCenterUnderConstruction()) {
				this.developButton.enable();
			}
			if(selectedAction != null){
				if(selectedAction instanceof BuildingAction){
					BuildingAction ba = (BuildingAction) selectedAction;
					if(!BuildingType.COMMAND_CENTER.equals(ba.getBuilding().getType())){
						// The selected action is not a command center construction
						selectedAction = null;
					}
				}else{
					// The action is not allowed yet
					selectedAction = null;
				}
			}
			this.buildWindow.setCommandCenterBuilt(false);
		}

		this.buildWindow.update(input);

		// Handle action drop
		if (this.selectedAction != null) {
			if (input.isMousePressed(Input.MOUSE_LEFT_BUTTON)
					&& this.mouseY > TOP_BAR_HEIGHT
					&& this.mouseY < Settings.HEIGHT - BOTTOM_BAR_HEIGHT) {
				final int tileX = this.squareXOnMap;
				final int tileY = this.squareYOnMap;
				if (this.selectedAction instanceof PreparationAction) {
					// Preparation action
					PreparationAction pa = (PreparationAction) this.selectedAction;
					boolean canBuild = false;
					if (TileHelper.tileIsPreparable(tileX, tileY)) {
						// Tile is OK
						if (ResourceHelper
								.enoughResourcesFor(SectorState.this.selectedAction
										.getCostMap())) {
							// Resources are OK
							if (GameData.getSelectedColony()
									.getAvailableRobots() > 0) {
								canBuild = true;
							}
						}
					}
					if (canBuild) {
						// Preparation can be done
						pa.setX(tileX);
						pa.setY(tileY);
						Map<Resource, BigDecimal> map = pa.getCostMap();
						for (Resource r : resources) {
							if (map.get(r) == null) {
								// No value defined for this resource
								continue;
							}
							GameData.getSelectedColony().updateResource(r,
									map.get(r).negate());
						}

						GameData.getSelectedColony().addPreparationAction(
								pa.clone());
					} else {
						// TODO play an error sound
					}

				} else if (this.selectedAction instanceof BuildingAction) {
					BuildingAction ba = (BuildingAction) this.selectedAction;
					if (BuildingType.COMMAND_CENTER.equals(ba.getBuilding()
							.getType())) {
						// Command center construction is handled in a submethod
						handleCommandCenterConstruction(ba, tileX, tileY);
					} else if (TileHelper.tileIsBuildable(tileX, tileY, ba
							.getBuilding().getType())) {
						// Is there already a building there?
						List<Building> buildings = GameData.getSelectedColony()
								.getBuildings();
						boolean canBuild = true;
						for (Building b : buildings) {
							if (b.getX() == tileX && b.getY() == tileY) {
								// Oops, there is already a building here.
								// Construction is impossible
								canBuild = false;
								break;
							}
						}
						// No building, but is there a building under
						// construction?
						List<BuildingAction> bactions = GameData
								.getSelectedColony().getBuildingActions();
						for (BuildingAction cba : bactions) {
							Building cb = cba.getBuilding();
							if (cb.getX() == tileX && cb.getY() == tileY) {
								// Construction is impossible
								canBuild = false;
								break;
							}
						}
						if (!ResourceHelper
								.enoughResourcesFor(SectorState.this.selectedAction
										.getCostMap())) {
							canBuild = false;
						}
						if (canBuild) {
							ba.getBuilding().setX(tileX);
							ba.getBuilding().setY(tileY);
							final BuildingAction nba = ba.clone();
							if (!BuildingType.ROAD.equals(nba.getBuilding()
									.getType())) {
								nba.setCallback(new Runnable() {

									@Override
									public void run() {
										if (nba.getBuilding()
												.equals(SectorState.this.selectedBuilding)) {
											SectorState.this.selectBuilding(nba
													.getBuilding());
										}
									}
								});
							}
							GameData.getSelectedColony().addBuildingAction(nba);
							// Remove from the stock the building cost
							BuildingData data = BuildingIO.getBuildingData(nba
									.getBuilding().getType());
							Map<Resource, BigDecimal> map = data
									.getLevelData(0).getUpgradeCost();
							for (Resource r : resources) {
								GameData.getSelectedColony().updateResource(r,
										map.get(r).negate());
							}
						} else {
							// TODO play an error sound
						}
					} else {
						// Cannot build here
					}
				}
			} else if (input.isMousePressed(Input.MOUSE_RIGHT_BUTTON)) {
				// Right clic when a building action is selected = deselect
				// building mode
				this.selectedAction = null;
			}
		}

		// Handle building selection
		handleBuildingSelection(input);

		// Building buttons
		for (int col = 0; col < 3; col++) {
			for (int row = 0; row < 3; row++) {
				this.buildingButtons[col][row].update(input);
			}
		}

		// Update the UIComponents
		for (UIComponent comp : this.components) {
			comp.update(input);
		}

		// Shortcuts handling
		handleShortcuts(input);

		//
		if (GameData.getSelectedColony().isResearchCenterBuilt()) {
			this.researchVisionButton.enable();
		} else {
			this.researchVisionButton.disable();
		}

		// If the Planet Exploration technology is researched, the Planet vision
		// is enabled
		if (GameData.getTechnologyMap().get("planet_exploration").isOwned()) {
			this.planetVisionButton.enable();
		} else {
			this.planetVisionButton.disable();
		}

		// Game logic update
		GameEngine.run(time);
	}

	private void handleShortcuts(Input input) {
		// Defined shortcuts :
		// - U : Upgrade the selected building
		// - B : Open the building panel
		// -
		// -
		// -
		if (this.selectedBuilding != null) {
			// Shortcut for building
			if (input.isKeyPressed(Input.KEY_U)) {
				// Upgrade wanted
				upgradeBuilding(this.selectedBuilding);
			}
		}

		if (!this.showActionWindow) {
			if (input.isKeyPressed(Input.KEY_B)) {
				showBuildWindow(true);
			}
		} else {
			// Building window is shown : handle building shortcuts
			if (input.isKeyPressed(Input.KEY_ESCAPE)) {
				showBuildWindow(false);
			} else {
				// Building shortcuts are defined in buildings
				for (BuildingType t : BuildingType.values()) {
					if (t.getShortcut() != -1
							&& input.isKeyPressed(t.getShortcut())) {
						// Building selected
						BuildingData data = BuildingIO.getBuildingData(t);
						BuildingAction ba = BuildingHelper.createAction(
								GameData.getSelectedColony(), t, data
										.getLevelData(0).getUpgradeCost());
						setSelectedAction(ba);
						showBuildWindow(false);
						break;
					}
				}
				// May be a robot shortcut?
				if (input.isKeyPressed(Input.KEY_A)) {
					// Robot action
					setSelectedAction(BuildingHelper.create(GameData
							.getSelectedColony()));
					showBuildWindow(false);
				}
			}
		}
	}

	private void showBuildWindow(boolean show) {
		this.showActionWindow = show;
		if (show) {
			this.buildWindow.show();
		} else {
			this.buildWindow.hide();
		}
	}

	/**
	 * This method create the scroll zones. Those zones will be used in the
	 * update method in order to trigger the scrolls.
	 */
	private void initializeScrollZones() {
		// Top zone
		int x = -1;
		int y = 0;
		int width = Settings.WIDTH + 2;
		int height = Settings.MAP_SCROLL_SENSITIVITY;
		this.topScrollZone = new Rectangle(x, y, width, height);

		// Bottom zone
		x = -1;
		y = Settings.HEIGHT - Settings.MAP_SCROLL_SENSITIVITY + 1;
		width = Settings.WIDTH + 2;
		height = Settings.MAP_SCROLL_SENSITIVITY + 1;
		this.bottomScrollZone = new Rectangle(x, y, width, height);

		// Left zone
		x = -1;
		y = 0;
		width = Settings.MAP_SCROLL_SENSITIVITY;
		height = Settings.HEIGHT + 2;
		this.leftScrollZone = new Rectangle(x, y, width, height);

		// Right zone
		x = Settings.WIDTH - Settings.MAP_SCROLL_SENSITIVITY;
		y = 0;
		width = Settings.MAP_SCROLL_SENSITIVITY + 1;
		height = Settings.HEIGHT + 2;
		this.rightScrollZone = new Rectangle(x, y, width, height);
	}

	/**
	 * Handle the scroll on the map
	 * 
	 * @param input
	 *            the player input
	 */
	private void handleScrollUpdate(Input input) {
		final int mouseX = input.getMouseX();
		final int mouseY = input.getMouseY();
		Colony c = GameData.getSelectedColony();
		// Vertical scroll
		if (this.topScrollZone.contains(mouseX, mouseY)) {
			c.setViewportY(c.getViewportY() + Settings.MAP_SCROLL_SPEED);
		} else if (this.bottomScrollZone.contains(mouseX, mouseY)) {
			c.setViewportY(c.getViewportY() - Settings.MAP_SCROLL_SPEED);
		}

		// Horizontal scroll
		if (this.leftScrollZone.contains(mouseX, mouseY)) {
			c.setViewportX(c.getViewportX() + Settings.MAP_SCROLL_SPEED);
		} else if (this.rightScrollZone.contains(mouseX, mouseY)) {
			c.setViewportX(c.getViewportX() - Settings.MAP_SCROLL_SPEED);
		}
	}

	/**
	 * Render the buildings on the map
	 * 
	 * @param g
	 *            the graphic canvas
	 * @throws SlickException
	 */
	private void renderBuildings(Graphics g) throws SlickException {
		// Built constructions
		List<Building> buildings = GameData.getSelectedColony().getBuildings();
		for (Building b : buildings) {
			Image gfx = null;
			if (BuildingType.ROAD.equals(b.getType())) {
				// Road are rendered according to the neighbors buildings
				gfx = UIHelper.getRoadGfx(b);
				gfx.draw(getScreenX(b.getX()), getScreenY(b.getY()));
			} else {
				gfx = ImageManager.getGfx(b.getType().toString());
				gfx.draw(getScreenX(b.getX()), getScreenY(b.getY()));
				if (b.equals(this.selectedBuilding)) {
					highlightBuilding(g, b);
				}
			}

		}

		// Constructions in progress
		List<BuildingAction> actions = GameData.getSelectedColony()
				.getBuildingActions();
		for (BuildingAction action : actions) {
			Building b = action.getBuilding();
			Image gfx = null;
			if (BuildingType.ROAD.equals(b.getType())) {
				// Road are rendered according to the neighbors buildings
				gfx = UIHelper.getRoadGfx(b);
			} else {
				gfx = ImageManager.getGfx(b.getType().toString());
			}
			gfx.draw(getScreenX(b.getX()), getScreenY(b.getY()), new Color(
					0.5F, 0.5F, 0.5F, 0.5F));

			// Render the construction progress bar
			int progress = action.getProgression();
			int x = getScreenX(b.getX());
			int y = getScreenY(b.getY());
			int width = NumberHelper.ruleOf3(100, Settings.TILE_SIZE, progress);

			if (action.isUpgrade()) {
				// Update : yellow
				g.setColor(Color.magenta);
			} else {
				// Creation : red
				g.setColor(Color.red);
			}
			g.drawLine(x, y, x + width, y);
			g.drawLine(x, y + 1, x + width, y + 1);
			g.drawLine(x, y + 2, x + width, y + 2);

			if (b.equals(this.selectedBuilding)) {
				highlightBuilding(g, b);
			}
		}

		// Robots
		List<PreparationAction> robotActions = GameData.getSelectedColony()
				.getPreparationActions();
		for (PreparationAction a : robotActions) {
			Image gfx = ImageManager.getGfx(a.getGfxKey());
			gfx.draw(getScreenX(a.getX()), getScreenY(a.getY()));

			// Render the construction progress bar
			int progress = a.getProgression();
			int x = getScreenX(a.getX());
			int y = getScreenY(a.getY());
			int width = NumberHelper.ruleOf3(100, Settings.TILE_SIZE, progress);

			g.setColor(Color.red);
			g.drawLine(x, y, x + width, y);
			g.drawLine(x, y + 1, x + width, y + 1);
			g.drawLine(x, y + 2, x + width, y + 2);
		}
	}

	/**
	 * Transform a screen coordinate to a map coordinate
	 * 
	 * @param mouseXOnScreen
	 *            The X coordinate of the mouse on the screen
	 * @return the X coordinate of the mouse on the map
	 */
	private int getMouseXOnMap(int mouseXOnScreen) {
		return -GameData.getSelectedColony().getViewportX() + mouseXOnScreen;
	}

	/**
	 * Transform a screen coordinate to a map coordinate
	 * 
	 * @param mouseYOnScreen
	 *            The Y coordinate of the mouse on the screen
	 * @return the Y coordinate of the mouse on the map
	 */
	private int getMouseYOnMap(int mouseYOnScreen) {
		return -GameData.getSelectedColony().getViewportY() + mouseYOnScreen;
	}

	/**
	 * Take a coordinate from the map and convert it to screen coordinate
	 * 
	 * @param mapX
	 *            the X coordinate
	 * @return the screen X coordinate
	 */
	private int getScreenX(int mapX) {
		return mapX * Settings.TILE_SIZE
				+ GameData.getSelectedColony().getViewportX();
	}

	/**
	 * Take a coordinate from the map and convert it to screen coordinate
	 * 
	 * @param mapY
	 *            the Y coordinate
	 * @return the screen Y coordinate
	 */
	private int getScreenY(int mapY) {
		return mapY * Settings.TILE_SIZE
				+ GameData.getSelectedColony().getViewportY();
	}

	/**
	 * Render a highligh on the given building
	 * 
	 * @param g
	 *            The graphic canvas
	 * @param b
	 *            The building to highlight
	 */
	private void highlightBuilding(Graphics g, Building b) {
		final int tileSize = Settings.TILE_SIZE - 1;
		g.setColor(Color.red);
		g.drawRect(getScreenX(b.getX()), getScreenY(b.getY()), tileSize,
				tileSize);
	}

	/**
	 * Render robots currently preparing the ground
	 * 
	 * @param g
	 *            the graphic canvas
	 * @throws SlickException
	 */
	private void renderRobots(Graphics g) throws SlickException {
		List<PreparationAction> actions = GameData.getSelectedColony()
				.getPreparationActions();
		for (PreparationAction a : actions) {
			Image gfx = ImageManager.getGfx("terrabot");
			gfx.draw(getScreenX(a.getX()), getScreenY(a.getY()));
		}
	}

	/**
	 * This method handles resource rendering. For each resource, a progress bar
	 * will be rendered representing the store space used. The last modifier
	 * applyed on the resource will also be rendered
	 * 
	 * @param g
	 *            the graphic canvas
	 * @param ox
	 *            the x origin for the render of this area
	 * @param oy
	 *            the y origin for the render of this area
	 * @throws SlickException
	 */
	private void renderProgressBars(Graphics g, int ox, int oy)
			throws SlickException {
		final int padding = 3;
		int pitch = 106 + 24;
		int x = ox;
		BigDecimal inStore;
		BigDecimal max;
		StringBuilder builder = new StringBuilder();
		Resource[] resources = Resource.values();
		ProgressBar pb;
		Map<Resource, BigDecimal> modifiers = GameData.getSelectedColony()
				.getLastModifiers();
		BigDecimal modifier;

		// Progress bar of robots use
		UIHelper.drawDarkBox(g, x + padding, oy + padding, 24, 20);
		Image img = ImageManager.getGfx("robot-small");
		img.draw(x + padding + 2, oy + padding);
		BigDecimal maxVal = BigDecimal.valueOf(GameData.getSelectedColony()
				.getTotalRobots());
		BigDecimal curVal = BigDecimal.valueOf(GameData.getSelectedColony()
				.getAvailableRobots());
		this.robotBar.setMaxValue(maxVal);
		this.robotBar.setValue(curVal);
		this.robotBar.setX(x + padding + 24);
		this.robotBar.setY(oy + padding);
		this.robotBar.render(g);

		// Rendering values
		// builder.setLength(0);
		// builder.append(curVal).append("/").append(maxVal);
		// font.drawString(x + padding, oy + 22, builder.toString());
		final int padd = 18;

		// Rendering of the rows titles
		int y = oy + 25;
		this.storeTitle.setPosition(x, y);
		y += padd;
		this.modifierTitle.setPosition(x, y);
		y += padd;
		this.availableSpaceTitle.setPosition(x, y);
		y += padd;
		this.maxStoreTitle.setPosition(x, y);

		x += pitch;
		for (Resource r : resources) {
			// Retreiving data
			inStore = GameData.getSelectedColony().getResource(r);
			max = GameData.getSelectedColony().getStorSpace(r);
			final int availableSpace = max.subtract(inStore).intValue();

			UIHelper.drawDarkBox(g, x + padding, oy + padding, 24, 20);
			img = ImageManager.getGfx(r.getGfxBase() + "-small");
			img.draw(x + padding + 2, oy + padding);
			// Creating and rendering the progress bar
			pb = this.resourceBars.get(r);
			pb.setX(x + padding + 24);
			pb.setY(oy + padding);
			pb.setMaxValue(max);
			pb.setValue(inStore);
			pb.render(g);

			// Rendering the resource amount, max and modifier
			if (this.extendedResourceDisplay) {
				y = oy + 25;

				// Currently in store
				String temp = inStore.setScale(0, BigDecimal.ROUND_FLOOR)
						.toString();
				Label current = this.inStoreLabels.get(r);
				drawResourceData(g, x + padding, y + 2, temp, current);
				y += padd;

				// Modifiers
				builder.setLength(0);
				modifier = modifiers.get(r);
				if (modifier.signum() == -1) {
					// Negative value
					builder.append("-");
				} else if (modifier.signum() == 1) {
					// Positive value
					builder.append("+");
				}
				builder.append(modifier);
				Label modifierLabel = this.modifiersLabels.get(r);
				drawResourceData(g, x + padding, y + 2, modifier.toString(),
						modifierLabel);
				y += padd;

				// Available space
				Label availableLabel = this.availableSpaceLabels.get(r);
				drawResourceData(g, x + padding, y + 2,
						String.valueOf(availableSpace), availableLabel);
				y += padd;

				// Max
				temp = max.toString();
				Label maxLabel = this.maxStoreLabels.get(r);
				drawResourceData(g, x + padding, y + 2, temp, maxLabel);
			}

			x += pitch;
		}
	}

	/**
	 * Draws the black box behind resources values and move the label at the
	 * right position
	 * 
	 * @param g
	 *            The graphic canvas
	 * @param x
	 *            The X coordinate
	 * @param y
	 *            The Y coordinate
	 * @param value
	 *            The string representation of the resource value
	 * @param label
	 *            The label
	 * @throws SlickException
	 */
	private void drawResourceData(Graphics g, int x, int y, String value,
			Label label) throws SlickException {
		final int zoneHeight = 15;
		UIHelper.drawDarkBox(g, x, y, label.getWidth() + 4, zoneHeight);
		label.setPosition(x, y);
		label.setText(value);
		label.setVisible(true);
	}

	/**
	 * 
	 * @param action
	 */
	public void setSelectedAction(MapAction action) {
		this.selectedAction = action;
		showBuildWindow(false);
	}

	/**
	 * According to the last mouse position on screen, get the X coordinate of
	 * the hovered square on the map
	 * 
	 * @param mouseXOnMap
	 *            X coordinate of the mouse on the map
	 * @return X coordinate of the hovered square on the map
	 */
	private int getHoveredSquareX(int mouseXOnMap) {
		return mouseXOnMap - (mouseXOnMap % 32)
				+ GameData.getSelectedColony().getViewportX();
	}

	/**
	 * According to the last mouse position on screen, get the Y coordinate of
	 * the hovered square on the map
	 * 
	 * @param mouseYOnMap
	 *            Y coordinate of the mouse on the map
	 * @return Y coordinate of the hovered square on the map
	 */
	private int getHoveredSquareY(int mouseYOnMap) {
		return mouseYOnMap - (mouseYOnMap % 32)
				+ GameData.getSelectedColony().getViewportY();
	}

	/**
	 * Handle the building selected area with the proper data
	 * 
	 * @param input
	 *            The player input
	 */
	private void handleBuildingSelection(Input input) {
		// Handle the building selection on the map only if the mouse is on the
		// viewport
		Rectangle zone = new Rectangle(0, TOP_BAR_HEIGHT, Settings.WIDTH,
				Settings.HEIGHT - TOP_BAR_HEIGHT - BOTTOM_BAR_HEIGHT);
		if (input.isMousePressed(Input.MOUSE_LEFT_BUTTON)
				&& zone.contains(this.mouseX, this.mouseY)) {
			selectBuilding(GameData.getSelectedColony().getBuildingAt(
					this.squareXOnMap, this.squareYOnMap));

			if (this.selectedBuilding != null) {
				if (BuildingType.ROAD.equals(this.selectedBuilding.getType())) {
					// For now, road are not selectable.
					// TODO Handle selectable buildings properly
					selectBuilding(null);
				} else {
					// The center button must be updated with the building gfx
					// this.buildCenterButton.setImageRef(this.selectedBuilding
					// .getType().toString());
					// this.buildCenterButton
					// .setActionHandler(new ActionHandler() {
					//
					// @Override
					// public void run() {
					// Move the viewport to the building
					// centerVieportOn(
					// PlayState.this.selectedBuilding
					// .getX()
					// * Settings.TILE_SIZE,
					// PlayState.this.selectedBuilding
					// .getY()
					// * Settings.TILE_SIZE);
					// }
					// });
				}
			}
		}
	}

	/**
	 * Render the selected building's attributes
	 * 
	 * @param g
	 *            The graphic canvas
	 * @throws SlickException
	 */
	private void renderBuildingAttributes(Graphics g) throws SlickException {
		final int ox = 150 + PADDING * 2;
		final int oy = Settings.HEIGHT - 116 - PADDING;

		// Building stats
		final int pitchX = 88;
		final int pitchY = 22;
		final int startX = ox + PADDING;
		int x = ox + pitchX;
		int y = oy;

		// Columns labels
		for (int col = 0; col < 3; col++) {
			Label lbl = this.buildingColLabels[col];
			lbl.setVisible(true);
			lbl.setPosition(x, y);
			x += pitchX;
		}

		y += 25;
		x = startX;

		BuildingData data = BuildingIO.getBuildingData(this.selectedBuilding
				.getType());
		BuildingLevelData levelData = data.getLevelData(this.selectedBuilding
				.getLevel());
		Map<Resource, BigDecimal> prod = levelData.getProduction();
		Map<Resource, BigDecimal> cons = levelData.getConsumption();
		Map<Resource, BigDecimal> store = levelData.getStoreCapacity();
		Resource[] resources = Resource.values();
		for (Resource r : resources) {
			// TODO Row label
			Label rowLabel = this.buildingRowLabels.get(r);
			rowLabel.setVisible(true);
			rowLabel.setPosition(x, y);
			x += pitchX;

			// Production
			Label prodLabel = this.buildingProdLabels.get(r);
			String prodValue = prod.get(r).toString();
			drawResourceData(g, x, y, prodValue, prodLabel);

			// Consumption
			Label consLabel = this.buildingConsLabels.get(r);
			String consValue = cons.get(r).toString();
			drawResourceData(g, x += pitchX, y, consValue, consLabel);

			// Store provided
			Label storeLabel = this.buildingStoreLabels.get(r);
			String storeValue = store.get(r).toString();
			drawResourceData(g, x += pitchX, y, storeValue, storeLabel);

			y += pitchY;
			x = startX;
		}
	}

	/**
	 * Render the building overview
	 * 
	 * @param g
	 *            The graphic canvas
	 * @throws SlickException
	 */
	private void renderBuildingOverview(Graphics g) throws SlickException {
		final int ox = 150 + PADDING * 2 + 368 + PADDING;
		final int oy = Settings.HEIGHT - Minimap.HEIGHT.intValue() - PADDING;

		UIHelper.drawDarkBox(g, ox + PADDING, oy + PADDING * 2 + 32, 33, 33);

		Image gfx = ImageManager.getGfx(this.selectedBuilding.getType()
				.toString().toLowerCase());
		gfx.draw(ox + PADDING + 1, oy + PADDING * 2 + 32);

		// Building name
		Font fontBig = FontHelper
				.getFont(FontHelper.HEMI_HEAD, Color.white, 30);
		Font fontNormal = FontHelper.getFont(FontHelper.HEMI_HEAD, Color.white,
				20);

		int x = ox + PADDING * 2 + 32;
		int y = oy + PADDING * 2;
		fontBig.drawString(x - 40, y, FontHelper.firstToUpper(I18n
				.get(this.selectedBuilding.getI18n())));

		// Building level
		String temp = I18n.get("global.level") + " : "
				+ this.selectedBuilding.getLevel();
		fontNormal.drawString(x, y += 40, FontHelper.firstToUpper(temp));

		// Current action
		String title = null;
		BigDecimal maxValue = null;
		BigDecimal value = null;
		DelayedAction a = getSelectedBuildingAction();
		this.selectedBuildingPB.setFilledColor(Color.red);
		if (a instanceof BuildingAction) {
			BuildingAction ba = (BuildingAction) a;
			if (ba.isUpgrade()) {
				// Upgrade process
				title = FontHelper.firstToUpper(I18n.get("global.upgrading"))
						+ "...";
				this.selectedBuildingPB.setFilledColor(Color.magenta);
			} else if (!ba.isUpgrade()) {
				// Building process
				title = FontHelper.firstToUpper(I18n.get("global.building"))
						+ "...";
			}
			maxValue = BigDecimal.valueOf(ba.getDuration());
			value = BigDecimal.valueOf(ba.getCurrentValue());
		} else if (a instanceof ColonyAction) {
			ColonyAction sa = (ColonyAction) a;
			title = FontHelper.firstToUpper(I18n.get(sa.getI18nKey())) + "...";
			this.selectedBuildingPB.setFilledColor(Color.red);
			maxValue = BigDecimal.valueOf(sa.getDuration());
			value = BigDecimal.valueOf(sa.getCurrentValue());
		}

		if (a != null) {
			fontNormal.drawString(x, y += 35, title);

			// Action progress
			this.selectedBuildingPB.setMaxValue(maxValue);
			this.selectedBuildingPB.setValue(value);
			this.selectedBuildingPB.setOX(x);
			this.selectedBuildingPB.setOY(y += 20);
			this.selectedBuildingPB.render(g);
		}

	}

	/**
	 * Select a building. By selecting a building (or unselecting one), the
	 * attributes labels will be shown or hidden
	 * 
	 * @param b
	 *            The building to select or null
	 */
	private void selectBuilding(Building b) {
		// Manage buttons visibility
		// Default buttons :
		// - Upgrade [0,2]
		// - Destroy [1,2]
		// - Cancel [2,2]
		// All buttons are hidden and disabled first, then, only useful buttons
		// are shown
		for (int col = 0; col < 3; col++) {
			for (int row = 0; row < 3; row++) {
				this.buildingButtons[col][row].hide();
				this.buildingButtons[col][row].disable();
			}
		}

		this.selectedBuilding = b;
		if (b == null) {
			// No building selected : hide buttons and labels
			Resource[] resources = Resource.values();
			for (Resource r : resources) {
				this.buildingConsLabels.get(r).setVisible(false);
				this.buildingProdLabels.get(r).setVisible(false);
				this.buildingStoreLabels.get(r).setVisible(false);
				this.buildingRowLabels.get(r).setVisible(false);
			}
			for (int i = 0; i < 3; i++) {
				this.buildingColLabels[i].setVisible(false);
			}
			return;
		}

		final boolean actionOngoing = this.getSelectedBuildingAction() != null;

		// Show useful buttons
		// Upgrade button is shown if there is another level for the building
		BuildingData data = BuildingIO.getBuildingData(this.selectedBuilding
				.getType());
		BuildingLevelData nextLevel = data.getLevelData(this.selectedBuilding
				.getLevel() + 1);
		if (nextLevel != null) {
			// There is a level
			this.buildingButtons[0][2].show();
			// Is it OK with technologies?
			if (TechnologyHelper.technologiesAreOwned(nextLevel
					.getTechnologiesNeeded())) {
				// OK but... Is there an action ongoing?
				if (!actionOngoing) {
					this.buildingButtons[0][2].enable();
				}
			}
		} else {
			// No more level : button stay hidden
		}

		// Cancel button is always shown but only enabled if an action is
		// currently being done
		this.buildingButtons[2][2].show();
		if (actionOngoing) {
			// There is an action to stop : enable the cancel button
			this.buildingButtons[2][2].enable();
		}
	}

	/**
	 * Stops the selected building action
	 */
	private void stopSelectedBuildingAction() {
		DelayedAction a = getSelectedBuildingAction();

		// Robot release
		GameData.getSelectedColony().releaseRobots(a.getRobotsUsed());

		// Deletion of the action in the GameData
		if (a instanceof BuildingAction) {
			BuildingAction ba = (BuildingAction) a;
			GameData.getSelectedColony().getBuildingActions().remove(ba);

			// If the action was a building then unselect the building
			if (ba.getBuilding().isUnderConstruction()) {
				// Call to selectBuilding method to handle buttons state
				// properly
				this.selectBuilding(null);

				// TODO Play destruction sound
			} else {
				// Call to selectBuilding method to handle buttons state
				// properly
				this.selectBuilding(this.selectedBuilding);
			}
		}

	}

	/**
	 * @return the action currently done by the building
	 */
	private DelayedAction getSelectedBuildingAction() {
		// Searching for building or upgrading action...
		List<BuildingAction> baList = GameData.getSelectedColony()
				.getBuildingActions();
		for (BuildingAction ba : baList) {
			if (ba.getBuilding().equals(this.selectedBuilding)) {
				return ba;
			}
		}

		// Searching for special action
		List<ColonyAction> saList = GameData.getSelectedColony()
				.getSpecialActions();
		for (ColonyAction sa : saList) {
			if (sa.getLinkedBuilding() != null
					&& sa.getLinkedBuilding().equals(this.selectedBuilding)) {
				return sa;
			}
		}
		return null;
	}

	/**
	 * Upgrade a building to it's next level. Checks resources first and then
	 * lunch an upgrade action
	 * 
	 * @param b
	 *            the building to upgrade
	 */
	private void upgradeBuilding(final Building b) {
		// Check resources
		BuildingLevelData levelData = BuildingIO.getBuildingData(b.getType())
				.getLevelData(b.getLevel());
		Map<Resource, BigDecimal> costMap = levelData.getUpgradeCost();
		// Enough resources ?
		if (ResourceHelper.enoughResourcesFor(costMap)) {
			Resource[] resources = Resource.values();
			for (Resource r : resources) {
				if (costMap.get(r) == null) {
					// No value defined for this resource
					continue;
				}
				GameData.getSelectedColony().updateResource(r,
						costMap.get(r).negate());
			}

			// Enough robots?
			if (GameData.getSelectedColony().getAvailableRobots() == 0) {
				// TODO Play error sound
				return;
			}

			// Create the action
			int duration = 5; // TODO extract into building config file
			BuildingAction ba = new BuildingAction(
					GameData.getSelectedColony(), costMap, b, duration, 1, true);
			ba.setCallback(new Runnable() {

				@Override
				public void run() {
					if (b.equals(SectorState.this.selectedBuilding)) {
						SectorState.this.selectBuilding(b);
					}
				}
			});

			GameData.getSelectedColony().addBuildingAction(ba);

			// Call to selectBuilding method to handle buttons state properly
			selectBuilding(b);
		} else {
			// TODO Play error sound
		}
	}

	/**
	 * Render a window with upgrade informations
	 * 
	 * @param costMap
	 *            The cost map of the upgrade
	 * @param g
	 *            The graphic canvas
	 * @throws SlickException
	 */
	protected void showUpgradeCost(Map<Resource, BigDecimal> costMap,
			Graphics g, ImageButton btn) throws SlickException {
		// Draw the BG
		final int width = 120;
		final int height = 101;
		final int box = btn.getOX();
		final int boy = btn.getOY();
		int x = box + btn.getWidth() / 2 - width / 2;
		int y = Settings.HEIGHT - BOTTOM_BAR_HEIGHT - height;
		UIHelper.drawBox(g, x, y, width, height);
		UIHelper.drawDarkBox(g, x += 3, y += 3, width - 6, height - 6);

		Resource[] resources = Resource.values();
		Image img;
		x += 3;
		for (Resource r : resources) {
			UIHelper.drawDarkBox(g, x, y += 3, 24, 20);
			img = ImageManager.getGfx(r.getGfxBase() + "-small");
			img.draw(x + 3, y, r.getColor());

			String value = costMap.get(r).toString();
			Label lbl = this.upgradeLabels.get(r);
			drawResourceData(g, x + 24, y, value, lbl);

			y += 20;
		}
	}

	/**
	 * Hide the labels in the upgrade overview window
	 */
	private void hideUpgradeLabels() {
		// Hide the labels
		Resource[] resources = Resource.values();
		for (Resource r : resources) {
			this.upgradeLabels.get(r).setVisible(false);
		}
	}

	private void handleCommandCenterConstruction(BuildingAction ba,
			final int tileX, final int tileY) {
		// If there is already a command center under construction, no mode
		// build action is handled (prevents from creating more than one command
		// center)
		if (GameData.getSelectedColony().isCommandCenterBuilt()) {
			return;
		}
		List<BuildingAction> actions = GameData.getSelectedColony()
				.getBuildingActions();
		for (BuildingAction a : actions) {
			if (BuildingType.COMMAND_CENTER.equals(a.getBuilding().getType())) {
				// There is already a command center under construction
				return;
			}
		}
		TiledMap map = GameData.getSelectedColony().getMap();
		final int mapWidth = map.getWidth();
		final int mapHeight = map.getHeight();

		if (!TileHelper.isValidCommandCenterTile(tileX, tileY)) {
			// TODO Play error sound
			// The zone is not correct for Command Center construction.
			return;
		}

		ba.getBuilding().setX(tileX);
		ba.getBuilding().setY(tileY);
		final BuildingAction nba = ba.clone();
		final Colony c = GameData.getSelectedColony();
		nba.setCallback(new Runnable() {

			@Override
			public void run() {
				BuildingHelper.createCMConstructionCallback(tileX, tileY, c);
			}
		});

		TileHelper.setTile(tileX, tileY, TileHelper.BUILDABLE_TILE,
				GameData.getSelectedColony());
		c.addBuildingAction(nba);

		// Construction is disabled until command center is fully built
		this.developButton.disable();

		// By the way the Command Center is unselected automatically when built
		this.selectedAction = null;
		GameData.getSelectedColony().setCommandCenterUnderConstruction(true);
	}

	@Override
	protected void renderTopZone(Graphics g) throws SlickException {
		int width = TOP_BAR_WIDTH + TOGGLE_BUTTON_ZONE_WIDTH;
		int height;
		if (this.extendedResourceDisplay) {
			height = 100;
		} else {
			height = 26;
		}
		int x = Settings.WIDTH / 2 - width / 2;
		int y = PADDING;
		UIHelper.drawWindow(g, x - 10, y - 10, width + 20, height + 20, 5);
		// UIHelper.drawBlackBox(g, x, y, width, height);

		renderProgressBars(g, x + TOGGLE_BUTTON_ZONE_WIDTH, y);

		// Render the colony name
		UIHelper.drawWindow(g, Settings.WIDTH - 140, 0, 140, 46, 5);
		Font font = FontHelper.getFont(FontHelper.HEMI_HEAD, Color.white, 20);
		font.drawString(Settings.WIDTH - 130, 15, GameData.getSelectedColony()
				.getName());
	}
}
